#include<iostream>
#include<cassert>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

#define MAX 1024
using namespace std;

//   管道的4中情况
//   1、正常情况，如果管道没有了数据，读端必须等待，直到有数据为止（写端写入了数据）
//   2、正常情况，如果管道被写满了，写端必须等待，直到有空间为止(读端读走数据)
//   3、写端关闭，读端一直读取, 读端会读到read返回值为0， 表示读到文件结尾
//   4、读端关闭，写端一直写入，OS会直接杀掉写端进程，通过想目标进程发送SIGPIPE(13)信号，终止目标进程



//   管道的5种特性
//   1、匿名管道,可以允许具有血缘关系的进程之间进行进程间通信，常用与父子,仅限于此
//   2、匿名管道，默认给读写端要提供同步机制 --- （了解现象）
//   3、面向字节流的 --- （了解现象）
//   4、管道的生命周期是随进程的
//   5、管道是单向通信的，半双工通信的一种特殊情况

int main()
{
    //第一步：建立管道

    int pipefd[2] = {0};
    int n=pipe(pipefd);
    assert(n==0);  //意料之中的错误用assert,意料之外的错误用if
    (void)n; //防止编译器警告
    cout<<"pipefd[0]:"<<pipefd[0]<<",pipefd[1]:"<<pipefd[1]<<endl;


    //第二步：创建子进程
    pid_t id = fork();
    if(id<0)
    {
        perror("fork");
        return 1;
    }
    //子进程写，父进程读


    //第三步：父子进程关闭不需要的fd，形成单向通信管道
    if(id==0)
    {
        //子进程干的事  写（w）
        close(pipefd[0]);
        int cnt=0;
        while(true)
        {
            char message[MAX];
            snprintf(message, sizeof(message), "hello father, I am child, pid: %d, cnt: %d", getpid(), cnt);
            cnt++;
            write(pipefd[1],message,strlen(message));
            sleep(1);
            if(cnt>10) break;
        }
        cout<<"child close w point"<<endl;
        exit(0);
    }
    //父进程干的事   读（r）
    close(pipefd[1]);
    char buffer[MAX];
    while(true)
    {
        ssize_t n=read(pipefd[0],buffer,sizeof(buffer)-1);
        if(n>0)
        {
            buffer[n] = 0; // '\0', 当做字符串
            cout << getpid() << ", " << "child say: " << buffer << " to me!" << endl;  
        }
        else if(n == 0)
        {
            cout << "child quit, me too !" << endl;
            break;
        }
        cout << "father return val(n): " << n << endl;
        sleep(1);

        break;
    }
    cout << "read point close"<< endl;
    close(pipefd[0]);
    
    sleep(5);
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if (rid == id)
    {
        cout << "wait success, child exit sig: " << (status&0x7F) << endl;
    }
    return 0;
}

